#include "BCSAMAIO.h"

//************************************
// Method:    	BCSAMAIO_PACK_Make		打包程序
// Programmer:  lww
// Time:		2019/1/2
// Returns:   	int						打包长度
// Parameter: 	void * Data				数据包头指针
// Parameter: 	short Head				报头
// Parameter: 	short Tail				报尾
// Parameter: 	int Limit_Len			单次数据包长度限制
// Parameter: 	short * SaveModel_Num	存储的模块的数量
//************************************
int BCSAMAIO_PACK_Make(void* Data, short Head, short Tail, int Limit_Len, short* SaveChannel_Num,int* SAMAIO_Total_Count, Card_Base_t* base)
{
#define MEMWRITE1(name)	MEMWRITE(name, Data);
	int _iLen = 0;
	short tmp_short;
	/*static int i = 0;*/						//< duan20200610注释
	void* Data1 = NULL;
	
	//< 报头
	MEMWRITE1(Head);

	//< 站号
	tmp_short = Station_ID;
	MEMWRITE1(tmp_short);

	//< 第三个数据存放从下一个数据开始从后数多少个字节为报尾，用于对报文的报尾进行校验，此处先保留该存储位置，稍后再对其进行存储
	Data1 = Data;
	tmp_short = 0;
	MEMWRITE1(tmp_short);
	_iLen = (int)(_iLen - sizeof(tmp_short));

	//< 第四个数据存储本次要广播的模块数量，这个数据等打包完成后最后写入，此处先保留该存储位置，稍后再对其进行存储
	MEMWRITE1(SaveChannel_Num[0]);
	_iLen = (int)(_iLen - sizeof(SaveChannel_Num[0]));

	if (base != NULL)
	{
		while ((SAMAIO_Total_Count[0] < (base->IO_Num.AO_Num + base->IO_Num.DO_Num)) && (_iLen < Limit_Len))
		{
			if (SAMAIO_Total_Count[0] < base->IO_Num.AO_Num)
				_iLen += BCAVIO(&(base->AOChannel[SAMAIO_Total_Count[0]]), &Data, SaveChannel_Num);
			else
				_iLen += BCDVIO(&(base->DOChannel[SAMAIO_Total_Count[0] - base->IO_Num.AO_Num]), &Data, SaveChannel_Num);
			SAMAIO_Total_Count[0]++;
		}
	}

	//< 写第三个数据
	tmp_short = (short)(_iLen - sizeof(Head) - sizeof(short) + sizeof(SaveChannel_Num[0]));//< 等于目前已经计数的长度减去报头，减去站号，加上要广播模块数量数据的长度
	MEMWRITE(tmp_short, Data1);

	//< 写第四个数据
	MEMWRITE(SaveChannel_Num[0], Data1);
	
	//< 报尾
	MEMWRITE1(Tail);
	return _iLen;
#undef MEMWRITE1
}


//************************************
// Method:    	tBCSAMAIO				广播IO软点线程
// Programmer:  lww
// Time:		2019/1/2
// Returns:   	void *
// Parameter: 	void * arg
//************************************
void *tBCSAMAIO(void* arg)
{
#define PACK_MAXNUM	2048 //<lijun20220802更改 由2048扩到8192
#define LIMIT_LEN	512
#define PORT (BCSAMAIO_PORT + 3*Station_ID)		//< duan0522 修改端口号  修改前：PORT (BCSAMAIO_PORT + 3*(Station_ID - 1))

	int sock;
	struct sockaddr_in NetA;
	struct sockaddr_in NetB;
	timer_t BCSAMAIO_Timer;
	struct timespec time;
	short Head = 7698;							//< 报头
	short Tail = 1444;							//< 报尾
	char Data2Send[PACK_MAXNUM];				//< 存放数据包的数组
	int _iLen = 0;
	short SaveChannel_Num = 0;					//< 当前数据包广播的通道数量
	static int SAMAIO_Total_Count = 0;			//< duan20200610添加
	Card_Base_t* base = NULL;					//< duan20200610添加

	printf("the Kernel_%s is %d\r\n", "tBCSAMAIO_ID", syscall(SYS_gettid));			//< duan20200610

	base = (Card_Base_t*)SearchId(((List_Base_t*)Card_List[TYP_SAMAIO].ppData[0]), SAMAIO_CARD_ID);
	//< 初始化UDP设置
	if (false == UDP_Init(&sock, (unsigned short)PORT, 0, 0, UDP_SEND_STATUS, nullptr)) { return 0; }

	//< 设置发送到的IP地址及端口
	Addr_Set(&NetA, (unsigned short)PORT, inet_addr(NETA_IP_BC));
	Addr_Set(&NetB, (unsigned short)PORT, inet_addr(NETB_IP_BC));

	//< 设置广播周期
	MS2TimeSpec(&time, BCSAMAIO_PERIOD);

	//< 开启定时中断
	Timer_Create(&BCSAMAIO_Timer, BcSamaIOSIG, &time);
	while (1)
	{
		//< 等待信号量释放进行广播操作
		/*MUTEX_LOCK(BcSamaIO_Mutex, "BcSamaIO_Mutex lock failed");*/
		SEM_WAIT(BcSamaIOSemId, "BcSamaIOSemId wait failed");

		if (SYS_Role == Master_Alone_Role || SYS_Role == Master_Twins_Role)
		{
			while (SAMAIO_Total_Count < (base->IO_Num.AO_Num + base->IO_Num.DO_Num))
			{
				SaveChannel_Num = 0;
				//< 数据打包
				//if (BCIODataFlg)
				_iLen = BCSAMAIO_PACK_Make(Data2Send, Head, Tail, LIMIT_LEN, &SaveChannel_Num, &SAMAIO_Total_Count, base);

				if (SaveChannel_Num > 0)
				{
					//< 发送数据
					UDP_Send(&sock, &NetA, (char*)Data2Send, _iLen);
					UDP_Send(&sock, &NetB, (char*)Data2Send, _iLen);
				}
			}
			if (SAMAIO_Total_Count >= (base->IO_Num.AO_Num + base->IO_Num.DO_Num))
				SAMAIO_Total_Count = 0;
		}
	}
	close(sock);//< 断开连接
#undef LIMIT_LEN
#undef PACK_MAXNUM
#undef PORT
}
